#include "hmi_private.h"

#include "esp_log.h"
#include "SD_MMC.h"
#include "buffer.h"

#define TAG "HMI"


OTAProcessor ota_processor;


OTAProcessor::OTAProcessor()
{
    // 创建两个二进制信号量
    semaphore_11 = xSemaphoreCreateBinary();
    semaphore_22 = xSemaphoreCreateBinary();
}
OTAProcessor::~OTAProcessor()
{
    // 删除信号量，释放资源
    if (semaphore_11)
    {
        vSemaphoreDelete(semaphore_11);
    }
    if (semaphore_22)
    {
        vSemaphoreDelete(semaphore_22);
    }
}
void OTAProcessor::begin()
{
    if(isRunning()){
        log_e("OTAProcessor is running!");
        return;
    }
    send_cmd_start();
    sended_size = 0;
    err = (0);
    sn = (0);
    buf.clear();
    header.clear();
    cmdB6.clear();
    cmd8822.clear();
    checksum.clear();
    packet.clear();
    setName("OTAProcessor");
    setPriority(5);
    start();
}

void OTAProcessor::end()
{
    stop();
}

void OTAProcessor::run(void *data) // 发送数据;
{
    start_time = millis();
    header.append_u8(0xEE);
    cmdB6.append_u8(0xB6);
    cmd8822.append_u8(0x88);
    cmd8822.append_u8(0x22);
    File file = SD_MMC.open("/ota.bin", FILE_READ);
    if (!file)
    {
        log_e("Failed to open file for reading");
        return;
    }

    // 3 秒超时时间，转换为 FreeRTOS 的 ticks
    const TickType_t timeout = pdMS_TO_TICKS(3000);

    // 等待 0x11 响应，设置 3 秒超时
    if (semaphore_11 && xSemaphoreTake(semaphore_11, timeout) == pdTRUE)
    {
        while (true)
        {
            size_t bytes_read = file.read(rbuf, packet_size);
            if (bytes_read == 0)
            {
                break;
            }
            // log_i("sdcard read data:%d", bytes_read);
            len = 2 + 1 + bytes_read + 2;

            // 构建数据包;
            buf.append(cmdB6);
            buf.append_u16(len, Buffer::BigEnd);
            buf.append(cmd8822);
            buf.append_u8(sn);            // 序列号
            buf.append(rbuf, bytes_read); // 数据
            checksum.append_u16(calculate_checksum((uint8_t *)buf.data(), buf.size()), Buffer::BigEnd);

            buf.append(checksum);                        // 校验和
            buf.append_u8(0xFF);                         // 帧尾
            buf.append_u8(0xFC);                         // 帧尾
            buf.append_u8(0xFF);                         // 帧尾
            buf.append_u8(0xFF);                         // 帧尾
            Serial2.write(header.data(), header.size()); // 发送数据;
            Serial2.write(buf.data(), buf.size());       // 发送数据;
            // log_buf_i(buf.data(), buf.size());
            buf.clear(); // 清空缓冲区;
            checksum.clear();
            len = 0;
            sended_size += bytes_read;
            sn++; // 序列号自增;

            // 等待 0x22 响应，设置 3 秒超时
            if (semaphore_22 && xSemaphoreTake(semaphore_22, timeout) == pdTRUE)
            {
                continue;
            }
            else
            {
                log_i("Wait for 0x22 ack timeout or failed!");
                err = -3; // 标记错误代码
                break;
            }
        }
    }
    else
    {
        log_i("Wait for 0x11 ack timeout or failed!");
        err = -2; // 标记错误代码
    }

    file.close();
    if (err)
    {
        // 可以在这里添加更多的错误处理逻辑，比如重试或者通知上层
        log_i("Run method failed with error code: %d", err);
    }
    else
    {
        log_i("send ota.bin successfully. [%ds]", (millis() - start_time) / 1000);
        send_cmd_update(); // 发送升级命令;
    }
    end();

}

// header = bytes.fromhex("EE B6")
// command_code = bytes.fromhex("8811")
// baudrate_bytes = baudrate.to_bytes(4, byteorder='big')
// filesize_bytes = filesize.to_bytes(4, byteorder='big')
// down_name_bytes = down_name.encode()
// # 计算 Len
// len_value = len(command_code) + len(baudrate_bytes) + len(filesize_bytes) + len(down_name_bytes)
// len_bytes = len_value.to_bytes(2, byteorder='big')
// # 构建完整命令
// footer = bytes.fromhex("FF FC FF FF")
// command = header + len_bytes + command_code + baudrate_bytes + filesize_bytes + down_name_bytes + footer
void OTAProcessor::send_cmd_start()
{
    Buffer header;          // 帧头;
    Buffer command_code;    // 命令码;
    Buffer baudrate_bytes;  // 波特率;
    Buffer filesize_bytes;  // 文件大小;
    Buffer down_name_bytes; // 下载名称;
    Buffer len_bytes;       // Len;
    Buffer footer;          // 帧尾;
    Buffer buf;             // 完整命令;

    File f = SD_MMC.open("/ota.bin", FILE_READ);

    header.append_u8(0xEE);
    header.append_u8(0xB6);
    command_code.append_u8(0x88);
    command_code.append_u8(0x11);
    baudrate_bytes.append_u32(115200, Buffer::BigEnd);                                                                                  // 波特率
    filesize_bytes.append_u32(f.size(), Buffer::BigEnd);                                                                                // 文件大小
    down_name_bytes.append("ota.bin");                                                                                                  // 下载名称长度
    len_bytes.append_u16(command_code.size() + baudrate_bytes.size() + filesize_bytes.size() + down_name_bytes.size(), Buffer::BigEnd); // Len
    footer.append_u8(0xFF);
    footer.append_u8(0xFC);
    footer.append_u8(0xFF);
    footer.append_u8(0xFF);

    buf.append(header.data(), header.size());                   // 帧头;
    buf.append(len_bytes.data(), len_bytes.size());             // Len;
    buf.append(command_code.data(), command_code.size());       // 命令码;
    buf.append(baudrate_bytes.data(), baudrate_bytes.size());   // 波特率;
    buf.append(filesize_bytes.data(), filesize_bytes.size());   // 文件大小;
    buf.append(down_name_bytes.data(), down_name_bytes.size()); // 下载名称;
    buf.append(footer.data(), footer.size());                   // 帧尾;

    f.close();
    Serial2.write(buf.data(), buf.size()); // 发送完整命令;

    log_i("OTA CMD send over");
}

// header = bytes.fromhex("EE B6")
// command_code = bytes.fromhex("883301")
// # 计算 Len
// len_value = len(command_code)
// len_bytes = len_value.to_bytes(2, byteorder='big')

// # 构建完整命令
// footer = bytes.fromhex("FF FC FF FF")
// command = header + len_bytes + command_code + footer

// # 打印命令的十六进制表示
// print("发送的下载命令（十六进制）:", command.hex())

// # 发送命令
// ser.write(command)
void OTAProcessor::send_cmd_update()
{

    Buffer header;       // 帧头;
    Buffer command_code; // 命令码;
    uint16_t len = 3;    // Len;
    Buffer footer;       // 帧尾;
    Buffer buf;          // 完整命令;

    header.append_u8(0xEE);
    header.append_u8(0xB6);
    command_code.append_u8(0x88);
    command_code.append_u8(0x33);
    command_code.append_u8(0x01);
    footer.append_u8(0xFF);
    footer.append_u8(0xFC);
    footer.append_u8(0xFF);
    footer.append_u8(0xFF);

    buf.append(header);                  // 帧头;
    buf.append_u16(len, Buffer::BigEnd); // Len;
    buf.append(command_code);            // 命令码;
    buf.append(footer);                  // 帧尾;

    Serial2.write(buf.data(), buf.size()); // 发送完整命令;
    log_i("OTA update cmd send over");
}
uint16_t OTAProcessor::calculate_checksum(uint8_t *data, uint16_t len)
{
    uint16_t sum = 0;
    for (uint16_t i = 0; i < len; i++)
    {
        sum += data[i];
    }
    sum = ~sum; // 取反
    return sum;
}



void OTAProcessor::on_ota_ack(uint8_t ctr_msg, uint8_t value)
{
    switch (ctr_msg)
    {
    case 0x11:
        if (value == 0X80)
        {
            // 释放 0x11 信号量
            if (semaphore_11)
            {
                xSemaphoreGive(semaphore_11);
            }
            // hmi_ota_data(); // 发送升级命令
        }
        else
        {
            log_i("send hmi_ota_start_cmd err:%d", value);
            err = (ctr_msg << 8) + value;
        }
        break;
    case 0x22:
        if (value == 0X80)
        {
            // 释放 0x22 信号量
            if (semaphore_22)
            {
                xSemaphoreGive(semaphore_22);
            }
        }
        else if (value == 0X82)
        {
            log_i("sn err");
            err = (ctr_msg << 8) + value;
        }
        else if (value == 0X83)
        {
            log_i("check sum err");
            err = (ctr_msg << 8) + value;
        }
        break;
    case 0x33:
        if (value == 0X80)
        {
            log_i("wait update");
        }
        break;
    case 0x55:
        if (value == 0X01)
        {
            log_i("ota.bin check ok");
        }
        else
        {
            log_i("ota.bin check err:%d", value);
            err = (ctr_msg << 8) + value;
        }
        break;
    case 0x66:
        if (value == 0X01)
        {
            log_i("ota.bin unzip ok!");
            log_i("screen restart!");
        }
        else
        {
            log_i("ota.bin unzip err:%d", value);
            err = (ctr_msg << 8) + value;
        }
        break;
    default:
        break;
    }
}
